package dk.aau.walkietalkieui;

import java.util.concurrent.TimeoutException;

import dk.aau.walkietalkie.database.DataEntriesAliveCounter;
import dk.aau.walkietalkie.network.ConnectivityChecker;
import dk.aau.walkietalkie.network.TCPServerFileTransfer;
import dk.aau.walkietalkie.network.UDPBroadcastReceiver;
import dk.aau.walkietalkie.network.UDPBroadcastSender;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.wifi.WifiManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View.OnCreateContextMenuListener;
import android.widget.Toast;

public class WalkieTalkieApplication extends Application {
	private static WalkieTalkieApplication instance;
	private static final int MAX_THREAD_WAIT_TIME = 1000;

	private Thread bcSenderThread;
	private Thread bcReceiverThread;
	private Thread deaCounterThread;
	private Thread fileTransferReceiverThread;

	private UDPBroadcastSender bcSender;
	private UDPBroadcastReceiver bcReceiver;
	private DataEntriesAliveCounter deaCounter;
	private TCPServerFileTransfer fileTransferReceiver;

	private IDBUpdateNotifier viewUpdater;

	public WalkieTalkieApplication() {
		instance = this;

		bcSender = new UDPBroadcastSender();
		fileTransferReceiver = new TCPServerFileTransfer();
		deaCounter = null;
		bcReceiver = null;
		viewUpdater = null;
	}

	public static Context getContext() {
		return instance;
	}

	public static WalkieTalkieApplication getApplication() {
		return instance;
	}
	
	public TCPServerFileTransfer getTranferReceiver() {
		return fileTransferReceiver;
	}

	public void startBroadcast() {
		bcSenderThread = new Thread(bcSender);
		bcSenderThread.start();
	}
	
	public void startFileReceiver() {
		fileTransferReceiverThread = new Thread(fileTransferReceiver);
		fileTransferReceiverThread.start();
	}

	public void setViewUpdater(IDBUpdateNotifier updateNotifier) {
		if (updateNotifier != null && viewUpdater == null) {
			viewUpdater = updateNotifier;
			bcReceiver = new UDPBroadcastReceiver(viewUpdater);
			deaCounter = new DataEntriesAliveCounter(viewUpdater);

			bcReceiverThread = new Thread(bcReceiver);
			bcReceiverThread.start();

			deaCounterThread = new Thread(deaCounter);
			deaCounterThread.start();
		} else if (updateNotifier != null) {
			// Threads are already started -> fragments were renewed
			bcReceiver.setUpdater(updateNotifier);
			deaCounter.setUpdater(updateNotifier);
		}
	}

	public void stopBroadcast() {
		bcSender.stopBroadcast();
		if (bcSenderThread != null) {
			try {
				bcSenderThread.join(MAX_THREAD_WAIT_TIME);
			} catch (InterruptedException e) {
				Log.e("Application",
						"BroadcastSender thread stopping timeout...");
				e.printStackTrace();
			}
			if (bcSenderThread.isAlive()) {
				bcSenderThread.interrupt();
			}

			bcSenderThread = null;
		}
	}
	
	public void stopFileReceiver() {
		fileTransferReceiver.stopFileTransferServer();
		if (fileTransferReceiverThread != null) {
			try {
				fileTransferReceiverThread.join(MAX_THREAD_WAIT_TIME);
			} catch (InterruptedException e) {
				Log.e("Application",
						"FileTransfer thread stopping timeout...");
				e.printStackTrace();
			}
			if (fileTransferReceiverThread.isAlive()) {
				fileTransferReceiverThread.interrupt();
			}

			fileTransferReceiverThread = null;
		}
	}

	private BroadcastReceiver wifiBroadcastReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			final String action = intent.getAction();
			if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
				if (intent.getBooleanExtra(
						WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
					// wifi connected -> start broadcast sender
					// wait first till network ready
					int wait = 0;
					boolean startBroadcast = true;
					while (!ConnectivityChecker.isWifiConnected(instance)) {
						try {
							Thread.sleep(500);
							wait++;
							Log.d("Application", "Waiting for network...");
							if (wait > 4) throw new TimeoutException();
						} catch (InterruptedException e) {
							e.printStackTrace();
							startBroadcast = false;
						} catch (TimeoutException e) {
							Toast.makeText(instance, "Network error: Timeout while waiting for WiFi to connect.", Toast.LENGTH_LONG).show();
							startBroadcast = false;
						}
					}
					// Start the broadcast thread only if the network is ready and working
					if (startBroadcast) startBroadcast();
					// in case the IP has changed now !!
					bcReceiver.updateOwnIP();
				} else {
					// wifi connection was lost -> deactivate the broadcast
					// not necessary because socket will throw exception
					stopBroadcast();
				}
			}
		}

	};

	public void onCreate() {
		IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
		registerReceiver(wifiBroadcastReceiver, intentFilter);

		// Start broadcasting thread if setting is enabled
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(instance);
		Boolean isOnline = sp.getBoolean("prefConnectionStatus", false);
		if (isOnline) {
			startBroadcast();
			startFileReceiver();
		}
	}
}